//
// Created by Administrator on 2022/11/10.
//
#include "app_evnet_list.h"
#include <errno.h>
#include <dirent.h>
#include <sys/sendfile.h>
#include <signal.h>
#include <unix/http_code.h>
#include <http_req_rep_com.h>

int _send_files(req_header_t * header, const char* fileName, int fdc);
int _send_dir(req_header_t * header, const char* fileName, int fdc);
int send_head_msg(req_header_t * header, int fdc, int status, const char* descr, const char* type, int length);

int file_system_app(struct requestContext *request){
//    sleep(1);
//    http_time_sleep(1);
    chdir(request->home);
    if(strcasecmp(request->reqType, "get") != 0){
        return -1;
    }
    char *file = NULL;
    if(strcmp(request->reqPath, "/") == 0){
        file = "./";
    }else{
        file = (request->reqPath + 1);
    }
    char file_name[PATH_MAX];
    unicode_decode(file_name, file);
    debug(request->rh->hset->logs, "file_system_app() filename is %s", file_name);
    struct stat st;
    int ret = stat(file_name, &st);
    if(ret == -1){
        // 文件不存在
        char errpath[PATH_MAX] = { 0 };
        char *errfile = "/html/404.html";
        send_head_msg(request->rh, request->fd, 404, "Not Found", get_http_mime_type(".html"), -1);
        http_memcpy(errpath, request->rh->hset->workpath, strlen(request->rh->hset->workpath));
        http_memcpy(errpath + strlen(request->rh->hset->workpath), errfile, strlen(errfile));
        _send_files(request->rh, errpath, request->fd);
        return TRUE;
    }
    if(S_ISDIR(st.st_mode)){
        // 把这个目录发给客户端
        send_head_msg(request->rh, request->fd, 200, "OK", get_http_mime_type(".html"), -1);
        _send_dir(request->rh, file_name, request->rh->fd);
    } else {
        // 把文件发送给客户端
        // 文件不存在
        send_head_msg(request->rh, request->rh->fd, 200, "OK", get_http_mime_type(file_name), st.st_size);
        _send_files(request->rh, file_name, request->rh->fd);
    }
    return TRUE;
}

int _send_files(req_header_t * header, const char* fileName, int fdc) {
    int ffd = open(fileName, O_RDONLY);
    debug(header->hset->logs, "打开文件：%d", ffd);
    if(ffd < 0){
        error(header->hset->logs, "_send_files fail %d : %s", ffd, strerror(errno));
    }
#if 1
    while (1) {
        char buf[1024];
        int len = read(ffd, buf, sizeof buf);
        if(len > 0) {
            int ret = noSgPutData(header->hset->logs, fdc, buf, len);
            if(ret == -1){
                if(errno == EPIPE){
                    debug(header->hset->logs, "_send_files: client close connect");
                    close(ffd);
                    return thread_err;
                }
            }
            usleep(10);
        }else if(len == 0){
            break;
        } else{
            error(header->hset->logs, "_send_files: %s", strerror(errno));
        }
    }
#else
    off_t offset = 0;
    int size = lseek(ffd, 0, SEEK_END);
    lseek(ffd, 0, 0);
    while(offset < size) {
        signal(SIGPIPE, SIG_IGN);
        int ret = sendfile(fdc, ffd, &offset, size);
        debug(header->hset->logs, "_send_files: over");
        if(ret == -1 && errno == EAGAIN){
            continue;
        } else if(ret == -1){
            debug(header->hset->logs, "_send_files: client close connect");
            close(ffd);
            return FALSE;
        }
    }
#endif
    debug(header->hset->logs, "_send_files: 数据处理完成 %d", fdc);
    close(ffd);
    debug(header->hset->logs, "关闭文件：%d", ffd);
    return TRUE;
}
int send_head_msg(req_header_t * header,  int fdc, int status, const char* descr, const char* type, int length){
    char buf[4096] = { 0 };
    char gmtstr[MAX_ERROR_STR];
    memset(gmtstr, 0, MAX_ERROR_STR);
    http_time_update(); // 更新时间
    http_cpymem(gmtstr, http_cached_gmt_time.data, http_cached_gmt_time.len);
    char repstr[1024] = { 0 };
    memset(repstr, 0, 1024);
    sprintf(buf, "http/1.1 %d %s\r\n", status, descr);
    sprintf(buf + strlen(buf),  "content-type: %s\r\n", type);
    if(length != -1){
        sprintf(buf + strlen(buf),  "content-length: %d\r\n", length);
    } else {
        sprintf(buf + strlen(buf),  "Tansfer-Encoding:chunke\r\n");
    }
    sprintf(buf + strlen(buf),  "Date: %s\r\n", gmtstr);
    sprintf(buf + strlen(buf),  "Server: TA&TO\r\n\r\n");
    noSgPutData(header->hset->logs, fdc, buf, strlen(buf));
    return TRUE;
}
int _send_dir(req_header_t * header, const char* fileName, int fdc) {
    char buf[4096] = { 0 };
    sprintf(buf, "<html><head><title>%s</title></head><body><table>", fileName);
    struct dirent** namelist;
    int num = scandir(fileName, &namelist, NULL, alphasort);
    for (int i = 0; i < num; ++i) {
        char *name = namelist[i]->d_name;
        char subPath[1024] = { 0 };
        struct stat st;
        sprintf(subPath, "%s/%s", fileName, name);
        stat(subPath, &st);
        if(S_ISDIR(st.st_mode)){
            sprintf(buf+ strlen(buf), "<tr><td><a href=\"%s/\">%s</a></td><td>%s</td><td>%ld</td></tr>", name, name, "directory", st.st_size);
        }else if(S_ISCHR(st.st_mode)){
            sprintf(buf+ strlen(buf), "<tr><td><a href=\"%s\">%s</a></td><td>%s</td><td>%ld</td></tr>", name, name, "char device", st.st_size);
        }else if(S_ISBLK(st.st_mode)){
            sprintf(buf+ strlen(buf), "<tr><td><a href=\"%s\">%s</a></td><td>%s</td><td>%ld</td></tr>", name, name, "block", st.st_size);
        }else if(S_ISREG(st.st_mode)){
            sprintf(buf+ strlen(buf), "<tr><td><a href=\"%s\">%s</a></td><td>%s</td><td>%ld</td></tr>", name, name, "file", st.st_size);
        }else if(S_ISFIFO(st.st_mode)){
            sprintf(buf+ strlen(buf), "<tr><td><a href=\"%s\">%s</a></td><td>%s</td><td>%ld</td></tr>", name, name, "fifo", st.st_size);
        }else if(S_ISLNK(st.st_mode)){
            sprintf(buf+ strlen(buf), "<tr><td><a href=\"%s\">%s</a></td><td>%s</td><td>%ld</td></tr>", name, name, "link", st.st_size);
        }else{
            sprintf(buf+ strlen(buf), "<tr><td><a href=\"%s\">%s</a></td><td>%s</td><td>%ld</td></tr>", name, name, "-", st.st_size);
        }
        noSgPutData(header->hset->logs, fdc, buf, strlen(buf));
        memset(buf, 0, strlen(buf));
        free(namelist[i]);
    }
    sprintf(buf, "</table></body></html>");
    noSgPutData(header->hset->logs, fdc, buf, strlen(buf));
    free(namelist);
    return TRUE;
}